package middleware

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"sync"
	"time"
)

// Session 表示一个用户会话
type Session struct {
	ID        string
	Data      map[string]interface{}
	ExpiresAt time.Time
}

// SessionManager 管理所有会话
type SessionManager struct {
	sessions map[string]*Session
	mutex    sync.RWMutex
}

var (
	sessionManager *SessionManager
	once           sync.Once
)

// GetSessionManager 获取会话管理器单例
func GetSessionManager() *SessionManager {
	once.Do(func() {
		sessionManager = &SessionManager{
			sessions: make(map[string]*Session),
		}
		// 启动会话清理goroutine
		go sessionManager.cleanupExpiredSessions()
	})
	return sessionManager
}

// CreateSession 创建新会话
func (sm *SessionManager) CreateSession() *Session {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	sessionID := generateSessionID()
	session := &Session{
		ID:        sessionID,
		Data:      make(map[string]interface{}),
		ExpiresAt: time.Now().Add(30 * time.Minute), // 30分钟过期
	}

	sm.sessions[sessionID] = session
	return session
}

// GetSession 获取会话
func (sm *SessionManager) GetSession(sessionID string) (*Session, bool) {
	sm.mutex.RLock()
	defer sm.mutex.RUnlock()

	session, exists := sm.sessions[sessionID]
	if !exists || time.Now().After(session.ExpiresAt) {
		return nil, false
	}
	return session, true
}

// DeleteSession 删除会话
func (sm *SessionManager) DeleteSession(sessionID string) {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	delete(sm.sessions, sessionID)
}

// SessionMiddleware 会话中间件
func SessionMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sessionManager := GetSessionManager()

		// 从cookie中获取session ID
		var session *Session
		cookie, err := r.Cookie("session_id")
		if err == nil && cookie.Value != "" {
			if s, exists := sessionManager.GetSession(cookie.Value); exists {
				session = s
				// 更新过期时间
				session.ExpiresAt = time.Now().Add(30 * time.Minute)
			}
		}

		// 如果没有session，创建新的
		if session == nil {
			session = sessionManager.CreateSession()
			// 设置session cookie
			http.SetCookie(w, &http.Cookie{
				Name:     "session_id",
				Value:    session.ID,
				Path:     "/",
				HttpOnly: true,
				Secure:   false, // 生产环境应该设置为true
				SameSite: http.SameSiteLaxMode,
				Expires:  session.ExpiresAt,
				MaxAge:   1800, // 30分钟
			})
		}

		// 将session存入context
		ctx := context.WithValue(r.Context(), "session", session)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// GetSessionFromRequest 从请求中获取会话
func GetSessionFromRequest(r *http.Request) (*Session, bool) {
	session := r.Context().Value("session")
	if session == nil {
		return nil, false
	}

	if s, ok := session.(*Session); ok {
		return s, true
	}
	return nil, false
}

// generateSessionID 生成随机会话ID
func generateSessionID() string {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		return fmt.Sprintf("%d", time.Now().UnixNano())
	}
	return base64.URLEncoding.EncodeToString(b)
}

// cleanupExpiredSessions 清理过期会话
func (sm *SessionManager) cleanupExpiredSessions() {
	ticker := time.NewTicker(5 * time.Minute)
	defer ticker.Stop()

	for range ticker.C {
		sm.mutex.Lock()
		now := time.Now()
		for id, session := range sm.sessions {
			if now.After(session.ExpiresAt) {
				delete(sm.sessions, id)
			}
		}
		sm.mutex.Unlock()
	}
}
